package com.hhkj.study.admin.user.service.biz.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hhkj.study.admin.course.service.extend.CourseExtendService;
import com.hhkj.study.admin.order.service.extend.OrderExtendService;
import com.hhkj.study.admin.resource.common.CommonValidateHandler;
import com.hhkj.study.admin.user.entity.User;
import com.hhkj.study.admin.user.entity.UserFollow;
import com.hhkj.study.admin.user.excel.UserExcelRes;
import com.hhkj.study.admin.user.model.podo.UserDo;
import com.hhkj.study.admin.user.model.podo.UserPo;
import com.hhkj.study.admin.user.model.req.UserCloseReq;
import com.hhkj.study.admin.user.model.req.UserFollowReq;
import com.hhkj.study.admin.user.model.req.UserReq;
import com.hhkj.study.admin.user.model.res.UserDetailRes;
import com.hhkj.study.admin.user.model.res.UserFollowRes;
import com.hhkj.study.admin.user.model.res.UserRes;
import com.hhkj.study.admin.user.service.base.UserFollowService;
import com.hhkj.study.admin.user.service.base.UserService;
import com.hhkj.study.admin.user.service.biz.UserBizService;
import com.hhkj.study.admin.user.service.biz.UserFollowBizService;
import com.hhkj.study.admin.user.service.extend.UserExtendService;
import com.hhkj.study.admin.user.service.extend.UserLoginExtendService;
import com.hhkj.study.common.cache.GlobalCache;
import com.hhkj.study.common.model.res.ExcelImportResultRes;
import com.ruoyi.common.base.biz.service.biz.BaseBizServiceImpl;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.cont.SysConst;
import com.ruoyi.common.exception.FieldValueBusinessException;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.excl.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
* UserBizServiceImpl
*
* @author SERVER
* @since 2024-09-06
*/
@Slf4j
@Service
public class UserBizServiceImpl extends BaseBizServiceImpl<User, UserReq, UserRes, UserDo, UserPo, UserService, UserExtendService> implements UserBizService {

    @Resource
    private GlobalCache globalCache;

    @Resource
    private UserFollowBizService userFollowBizService;

    @Resource
    private UserFollowService userFollowService;

    @Resource
    private OrderExtendService orderExtendService;

    @Resource
    private CourseExtendService courseExtendService;

    @Resource
    private UserLoginExtendService userLoginExtendService;

    @Resource
    private CommonValidateHandler commonValidateHandler;

    @Override
    public UserDetailRes getById(Long id) {
        UserPo user = this.getExtendService().getPoByIdNotNull(id);
        UserDetailRes userDetailRes = BeanUtil.toBean(user, UserDetailRes.class);
        Map<Long, String> dictMap = globalCache.cacheDictMap(Constants.REGION_COURSE_CODE_LIST);
        userDetailRes.setRealRegionName(dictMap.get(user.getRealRegionId()));
        userDetailRes.setIntentionalExam(dictMap.get(user.getIntentionalExamId()));
        userDetailRes.setCityName(dictMap.get(user.getCityId()));
        userDetailRes.setProvinceName(dictMap.get(user.getProvinceId()));
        // 补充用户其他信息
        supplyUser(userDetailRes);
        return userDetailRes;
    }

    @Override
    protected void beforeSave(UserReq userReq) {
        String pwd = StrUtil.subSufByLength(userReq.getMobile(), 6);
        userReq.setPassword(SecurityUtils.encryptPassword(pwd));
    }

    @Override
    protected void afterPage(List<UserRes> userResList) {
        Map<Long, String> dictMap = globalCache.cacheDictMap(Constants.REGION_COURSE_CODE_LIST);
        userResList.forEach(userRes -> {
            userRes.setRealRegionName(dictMap.get(userRes.getRealRegionId()));
            userRes.setIntentionalExam(dictMap.get(userRes.getIntentionalExamId()));
        });
    }

    @Override
    public boolean update(UserReq userReq) {
        return this.getService().updateById(userReq);
    }

    @Override
    public void export(UserReq req, HttpServletResponse response) {
        List<UserRes> userResList = list(req);
        if (CollectionUtil.isEmpty(userResList)) {
            throw new GlobalException("数据为空");
        }
        List<UserExcelRes> userExcelResList = BeanUtil.copyToList(userResList, UserExcelRes.class);
        assignUserExcelRes(userExcelResList);
        ExcelUtils.exportExcelRuoYi(response, userExcelResList, UserExcelRes.class, "用户信息", "用户信息");
    }



    @Override
    public ExcelImportResultRes importCustomerUser(MultipartFile file, HttpServletRequest request) {
        List<UserExcelRes> userExcelResList = ExcelUtils.importExcelRuoYi(file, UserExcelRes.class, 1);
        if (CollectionUtil.isEmpty(userExcelResList)) {
            throw new GlobalException("导入数据为空");
        }

        // 导入的数据校验
        ExcelImportResultRes excelImportResultRes = commonValidateHandler.commonValidate(userExcelResList, (userRes) -> checkFieldBusinessValid((UserExcelRes) userRes));
        if (CollectionUtil.isEmpty(excelImportResultRes.getErrorList())) {
            // 校验特定字段唯一性
            checkUnique(userExcelResList);
            List<User> userList = BeanUtil.copyToList(userExcelResList, User.class);
            this.getService().saveBatch(userList);
        }
        return excelImportResultRes;
    }


    @Override
    public boolean rePassword(Long id) {
        User user = this.getExtendService().getPoByIdNotNull(id);
        String newPassword = StrUtil.subSufByLength(user.getMobile(), 6);
        user.setPassword(SecurityUtils.encryptPassword(newPassword));
        return this.getService().updateById(user);
    }

    @Override
    public boolean updateDisable(UserCloseReq req) {
        User user = this.getExtendService().getByIdNotNull(req.getId());
        Integer disableFlag = SysConst.Flag.IS.getFlag().equals(user.getDisableFlag()) ? SysConst.Flag.NO.getFlag() : SysConst.Flag.IS.getFlag();
        LambdaUpdateWrapper<User> userUpdate = new LambdaUpdateWrapper<>();
        userUpdate.eq(User::getId, req.getId())
                .set(User::getDisableFlag, disableFlag).set(User::getDisableReason, req.getReason());
        return this.getService().update(userUpdate);
    }

    @Override
    public boolean remove(UserCloseReq req) {
        LambdaUpdateWrapper<User> userLambdaUpdate = new LambdaUpdateWrapper<>();
        userLambdaUpdate.in(User::getId, req.getIdList()).eq(User::getDelFlag, SysConst.Flag.NO.getFlag())
                .set(User::getDelFlag, SysConst.Flag.IS.getFlag()).set(User::getDelReason, req.getReason());
        return this.getService().update(userLambdaUpdate);
    }

    @Override
    public UserRes get(UserReq userReq) {
        return BeanUtil.toBean(this.getService().getPoByDo(userReq), UserRes.class);
    }

    /**
     * 校验字段唯一性
     * @param userExcelResList
     */
    private void checkUnique(List<UserExcelRes> userExcelResList) {
        // 获得导入中所有的手机号和身份证号,判断手机号和身份证不能重复
        Pair<List<String>, List<String>> mobileIdCardPair = userExcelResList.stream().collect(Collectors.collectingAndThen(
                Collectors.toList(),
                list -> {
                    List<String> mobileList = list.stream().map(UserExcelRes::getMobile).filter(StrUtil::isNotBlank).collect(Collectors.toList());
                    List<String> idCardList = list.stream().map(UserExcelRes::getIdCard).filter(StrUtil::isNotBlank).collect(Collectors.toList());
                    return Pair.of(mobileList, idCardList);
                }
        ));

        List<String> repeatMobileList = mobileIdCardPair.getLeft().stream().collect(Collectors.groupingBy(s -> s, Collectors.counting()))
                .entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        List<String> repeatIdCardList = mobileIdCardPair.getRight().stream().collect(Collectors.groupingBy(s -> s, Collectors.counting()))
                .entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        // 是否有重复数据标识
        boolean hasRepeat = false;
        StringBuilder errorMsg = new StringBuilder();
        if (CollectionUtil.isNotEmpty(repeatMobileList) || CollectionUtil.isNotEmpty(repeatIdCardList)) {

            if (CollectionUtil.isNotEmpty(repeatMobileList)) {
                hasRepeat = true;
                errorMsg.append("手机号重复: ").append(StrUtil.join(",", repeatMobileList)).append("; ");
            }
            if (CollectionUtil.isNotEmpty(repeatIdCardList)) {
                hasRepeat = true;
                errorMsg.append("身份证号重复: ").append(StrUtil.join(",", repeatIdCardList)).append("; ");
            }
        }
        if (hasRepeat) {
            throw new GlobalException(errorMsg.toString());
        }

    }

    /**
     * 校验用户业务参数
     * @param userExcelRes
     */
    private void checkFieldBusinessValid(UserExcelRes userExcelRes){
        if (StrUtil.isNotBlank(userExcelRes.getIdCard())) {
            if (!IdcardUtil.isValidCard(userExcelRes.getIdCard())) {
                throw new FieldValueBusinessException(userExcelRes.getIdCard() + "身份证号不合法");
            }
        }
        if (StrUtil.isNotBlank(userExcelRes.getMobile()) || StrUtil.isNotBlank(userExcelRes.getIdCard())) {
            User cusomerUser = this.getExtendService().getByMobileOrIdCard(userExcelRes.getMobile(), userExcelRes.getIdCard());
            if (ObjectUtil.isNotNull(cusomerUser)) {
                boolean isError = false;
                StringBuilder sb = new StringBuilder("用户");
                if (StrUtil.equals(userExcelRes.getMobile(), cusomerUser.getMobile())) {
                    sb.append("手机号").append(userExcelRes.getMobile()).append(StrUtil.COMMA);
                    isError = true;
                }
                if (StrUtil.equals(userExcelRes.getIdCard(), cusomerUser.getIdCard())) {
                    sb.append("身份证号").append(userExcelRes.getIdCard());
                    isError = true;
                }
                if (isError) {
                    String errorMsg = StrUtil.removeSuffix(sb, StrUtil.COMMA);
                    throw new FieldValueBusinessException(StrUtil.format("{}已存在", errorMsg));
                }
            }
        }
    }


    /**
     * 补充用户跟进记录 订单 课程
     * @param userDetailRes
     */
    private void supplyUser(UserDetailRes userDetailRes) {
        // 跟进记录
        UserFollowReq userFollowReq = new UserFollowReq();
        Long userId = userDetailRes.getId();
        userFollowReq.setUserId(userId);
        List<UserFollowRes> followList = userFollowBizService.list(userFollowReq);
        userDetailRes.setFollowRecordList(followList);

        // 订单记录
        userDetailRes.setOrderList(orderExtendService.listByUserId(userId));

        // 课程记录
        try {
            userDetailRes.setCourseList(courseExtendService.getCourseListByUserId(userId, null));
        } catch (Exception e) {
            log.warn("课程记录查询失败, 用户id为{}", userId, e);
        }
    }


    private void assignUserExcelRes(List<UserExcelRes> userExcelResList) {
        List<Long> userIdList = userExcelResList.stream().map(UserExcelRes::getId).collect(Collectors.toList());

        // 用户订单统计
        Map<Long, Pair<Integer, Integer>> userOrderMap = orderExtendService.statUserOrder(userIdList);

        // 用户当月最新跟进记录
        Date currentDate = new Date();
        LambdaQueryWrapper<UserFollow> userFollowQuery = new LambdaQueryWrapper<>();
        userFollowQuery.in(UserFollow::getUserId, userIdList).le(UserFollow::getFollowTime, DateUtil.endOfMonth(currentDate)).gt(UserFollow::getFollowTime, DateUtil.beginOfMonth(currentDate));
        List<UserFollow> userFollowList = userFollowService.list(userFollowQuery);
        Map<Long, Optional<UserFollow>> userIdFollowMap = userFollowList.stream().collect(Collectors.groupingBy(UserFollow::getUserId, Collectors.maxBy(Comparator.comparing(UserFollow::getFollowTime))));

        // 最后登录日志
        Map<Long, Date> userLastLoginTimeMap = userLoginExtendService.getLastLoginTimeMap(userIdList);

        userExcelResList.forEach(userExcelRes -> {
            userExcelRes.setLastLoginTime(userLastLoginTimeMap.get(userExcelRes.getId()));
            Pair<Integer, Integer> orderPair = userOrderMap.get(userExcelRes.getId());
            if (ObjectUtil.isNotNull(orderPair)) {
                userExcelRes.setOrderTotalCount(orderPair.getLeft());
                userExcelRes.setOrderTotalAmount(String.valueOf(orderPair.getRight()));
            }
            Optional<UserFollow> userFollowOptional = userIdFollowMap.get(userExcelRes.getId());
            // 如果不存在则表示该用户没有跟进记录
            if (ObjectUtil.isNotNull(userFollowOptional) && userFollowOptional.isPresent()) {
                userExcelRes.setCurrentMonthFollowFlag(SysConst.Flag.IS.getFlag());
                userExcelRes.setLastFollowContent(userFollowOptional.get().getContent());
            } else {
                userExcelRes.setCurrentMonthFollowFlag(SysConst.Flag.NO.getFlag());
            }
        });
    }
}